home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
IRIX 6.2 Applications 1996 May
/
SGI IRIX 6.2 Applications 1996 May.iso
/
dist
/
impr_dev.idb
/
usr
/
impressario
/
src
/
libimp
/
impOpen.c.z
/
impOpen.c
Wrap
C/C++ Source or Header
|
1996-05-06
|
35KB
|
1,115 lines
/**************************************************************************
*
* Copyright (c) 1993 Silicon Graphics, Inc.
* All Rights Reserved
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SGI
*
* The copyright notice above does not evidence any actual of intended
* publication of such source code, and is an unpublished work by Silicon
* Graphics, Inc. This material contains CONFIDENTIAL INFORMATION that is
* the property of Silicon Graphics, Inc. Any use, duplication or
* disclosure not specifically authorized by Silicon Graphics is strictly
* prohibited.
*
* RESTRICTED RIGHTS LEGEND:
*
* Use, duplication or disclosure by the Government is subject to
* restrictions as set forth in subdivision (c)(1)(ii) of the Rights in
* Technical Data and Computer Software clause at DFARS 52.227-7013,
* and/or in similar or successor clauses in the FAR, DOD or NASA FAR
* Supplement. Unpublished - rights reserved under the Copyright Laws of
* the United States. Contractor is SILICON GRAPHICS, INC., 2011 N.
* Shoreline Blvd., Mountain View, CA 94039-7311
**************************************************************************
*
* File: impOpen.c
*
* Description: Image file open routines.
*
**************************************************************************/
#ident "$Revision: 1.8 $"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include "impI.h"
/* Local functions */
static IMPImage* openImage(int fd, const char *fname, void *buf,
const char *mode, off_t offset, IMPCacheMode cache,
uint_t rasterType, uint_t dimension,
uint_t xSize, uint_t ySize,
uint_t numChannels, uint_t imageType, char *name);
static int initRLE(IMPImage *image, int fd, void *buf, const char *mode,
off_t offset);
static void errorCleanup(IMPImage *image, int fd, const char *fname);
static int readData(int fd, void *fromBuf, void *toBuf,
unsigned int amount, off_t offset);
static int writeData(int fd, void *fromBuf, unsigned int amount, off_t offset);
static void setCacheSize(IMPImage *image);
static void getTags(IMPImage *image, int fd, void *buf, off_t offset,
__uint32_t offsetTags);
/**************************************************************************
*
* Function: impOpen
*
* Description: Opens an SGI image file specified by name for reading
* or writing.
*
* Parameters:
* fname (I) - name of the file to open
* mode (I) - "r" for read-only, "w" for write-only. Note that
* read-write mode is not currently supported.
*
* If the mode is "w" the following parameters must be specified.
*
* rasterType (I) - raster encoding and bytes per pixel code
* (e.g. IMP_RASTER_VERBATIM1)
* dimesnion (I) - image dimension. Set this to 1 for a colormap,
* 2 for a bw image, and 3 for an rgb image.
* xSize, ySize (I) - image size in pixels.
* numChannels (I) - 1 for colormap or bw image, 3 for rgb.
* imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
* imp.h for additional choices.
* name (I) - optional image name. IMP_NAME_MAX characters maximum.
* Specify as NULL for a default name string.
*
* Return: Pointer to an SGI image file handle if the open is successful.
* NULL is returned and IMPerrno is set if the open fails.
*
**************************************************************************/
/* VARARGS */
IMPImage* impOpen(const char *fname, const char *mode, ...)
{
va_list ap;
uint_t rasterType, dimension;
uint_t xSize, ySize;
uint_t numChannels, imageType;
char *name;
/*
* Sanity check the inputs
*/
assert(fname != NULL);
assert(mode != NULL);
/*
* Get the arguments for the actual open function
*/
if (*mode == 'w') {
va_start(ap, mode);
rasterType = va_arg(ap, uint_t);
dimension = va_arg(ap, uint_t);
xSize = va_arg(ap, uint_t);
ySize = va_arg(ap, uint_t);
numChannels = va_arg(ap, uint_t);
imageType = va_arg(ap, uint_t);
name = va_arg(ap, char*);
va_end(ap);
}
/*
* Call the actual open function
*/
return (openImage(0, fname, NULL, mode, 0, IMPNoCache, rasterType,
dimension, xSize, ySize, numChannels, imageType,
name));
}
/**************************************************************************
*
* Function: impOpenFd
*
* Description: Opens an SGI image file specified by descriptor for reading
* or writing.
*
* Parameters:
* fd (I) - descriptor of the file.
* mode (I) - "r" for read-only, "w" for write-only. Read-write
* mode is not currently supported. Note that mode
* must be compatible with the mode on fd.
*
* If the mode is "w" the following parameters must be specified.
*
* rasterType (I) - raster encoding and bytes per pixel code
* (e.g. IMP_RASTER_VERBATIM1)
* dimesnion (I) - image dimension. Set this to 1 for a colormap,
* 2 for a bw image, and 3 for an rgb image.
* xSize, ySize (I) - image size in pixels.
* numChannels (I) - 1 for colormap or bw image, 3 for rgb.
* imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
* imp.h for additional choices.
* name (I) - optional image name. IMP_NAME_MAX characters maximum.
* Specify as NULL for a default name string.
*
* Return: Pointer to an SGI image file handle if the open is successful.
* NULL is returned and IMPerrno is set if the open fails.
*
**************************************************************************/
/* VARARGS */
IMPImage* impOpenFd(int fd, const char *mode, ...)
{
va_list ap;
uint_t rasterType, dimension;
uint_t xSize, ySize;
uint_t numChannels, imageType;
char *name;
struct stat sbuf;
/*
* Sanity check the inputs
*/
assert(mode != NULL);
/*
* Verify that the file descriptor is valid and
* is seekable. To test seekability we check that an
* lseek succeeds and that the descriptor is not connected
* to a tty. It turns out that the lseek test succeeds for
* a tty so we add the isatty test.
*/
if (fstat(fd, &sbuf) < 0)
_impReturnErrorPtr(IMP_ERR_BADFD);
if (lseek(fd, 0L, SEEK_CUR) < 0 || isatty(fd))
_impReturnErrorPtr(IMP_ERR_SEEK);
/*
* Get the arguments for the actual open function
*/
if (*mode == 'w') {
va_start(ap, mode);
rasterType = va_arg(ap, uint_t);
dimension = va_arg(ap, uint_t);
xSize = va_arg(ap, uint_t);
ySize = va_arg(ap, uint_t);
numChannels = va_arg(ap, uint_t);
imageType = va_arg(ap, uint_t);
name = va_arg(ap, char*);
va_end(ap);
}
/*
* Call the actual open function
*/
return (openImage(fd, NULL, NULL, mode, 0, IMPNoCache, rasterType,
dimension, xSize, ySize, numChannels, imageType,
name));
}
/**************************************************************************
*
* Function: impOpenBuf
*
* Description: Opens an SGI image file contained in a memory buffer for
* reading or writing.
*
* The user must not deallocate the buffer until all libimp operations
* are completed and impClose has been called.
*
* Parameters:
* buf (I) - pointer to buffer hodling image
* mode (I) - "r" for read-only, "w" for write-only. Read-write
* mode is not currently supported. Note that mode
* must be compatible with the mode on fd.
*
* If the mode is "w" the following parameters must be specified.
*
* rasterType (I) - raster encoding and bytes per pixel code
* (e.g. IMP_RASTER_VERBATIM1)
* dimesnion (I) - image dimension. Set this to 1 for a colormap,
* 2 for a bw image, and 3 for an rgb image.
* xSize, ySize (I) - image size in pixels.
* numChannels (I) - 1 for colormap or bw image, 3 for rgb.
* imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
* imp.h for additional choices.
* name (I) - optional image name. IMP_NAME_MAX characters maximum.
* Specify as NULL for a default name string.
*
* Return: Pointer to an SGI image file handle if the open is successful.
* NULL is returned and IMPerrno is set if the open fails.
*
**************************************************************************/
/* VARARGS */
IMPImage* impOpenBuf(void *buf, const char *mode, ...)
{
uint_t rasterType, dimension;
uint_t xSize, ySize;
uint_t numChannels, imageType;
char *name;
/*
* Sanity check the inputs
*/
assert(buf != NULL);
assert(mode != NULL);
/*
* Image write to a buffer not currently supported. This is because
* it is not possible to know up front how big the buffer should be
* before you write into it. This is due to RLE compressarion possibly
* making the file larger than its dimensions would suggest.
*/
if (*mode == 'w')
_impReturnErrorPtr(IMP_ERR_NOWRITE);
/*
* Call the actual open function
*/
return (openImage(0, NULL, buf, mode, 0, _IMPBufDirect, rasterType,
dimension, xSize, ySize, numChannels, imageType,
name));
}
/**************************************************************************
*
* Function: impOpenExt
*
* Description: Opens an SGI image file specified by name for reading
* or writing. The Ext (extended) form of the impOpen function
* allows an offset into the image file to be specified. In addition
* the image may be cached in memory when in read-only mode.
*
* Parameters:
* fname (I) - name of the file to open
* mode (I) - "r" for read-only, "w" for write-only. Note that
* read-write mode is not currently supported.
* offset (I) - number of bytes from the start of the file where
* reading or writing is to begin.
* cache (I) - if IMPCache and mode is read-only, the entire image
* will be cached in memory. If IMPNoCache or
* mode is write-only, no caching is done.
*
* If the mode is "w" the following parameters must be specified.
*
* rasterType (I) - raster encoding and bytes per pixel code
* (e.g. IMP_RASTER_VERBATIM1)
* dimesnion (I) - image dimension. Set this to 1 for a colormap,
* 2 for a bw image, and 3 for an rgb image.
* xSize, ySize (I) - image size in pixels.
* numChannels (I) - 1 for colormap or bw image, 3 for rgb.
* imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
* imp.h for additional choices.
* name (I) - optional image name. IMP_NAME_MAX characters maximum.
* Specify as NULL for a default name string.
*
* Return: Pointer to an SGI image file handle if the open is successful.
* NULL is returned and IMPerrno is set if the open fails.
*
**************************************************************************/
/* VARARGS */
IMPImage* impOpenExt(const char *fname, const char *mode, off_t offset,
IMPCacheMode cache, ...)
{
va_list ap;
uint_t rasterType, dimension;
uint_t xSize, ySize;
uint_t numChannels, imageType;
char *name;
/*
* Sanity check the inputs
*/
assert(fname != NULL);
assert(mode != NULL);
/*
* Get the arguments for the actual open function
*/
if (*mode == 'w') {
va_start(ap, cache);
rasterType = va_arg(ap, uint_t);
dimension = va_arg(ap, uint_t);
xSize = va_arg(ap, uint_t);
ySize = va_arg(ap, uint_t);
numChannels = va_arg(ap, uint_t);
imageType = va_arg(ap, uint_t);
name = va_arg(ap, char*);
va_end(ap);
/*
* We do not do caching for image writes
*/
cache = IMPNoCache;
}
/*
* Call the actual open function
*/
return (openImage(0, fname, NULL, mode, offset, cache, rasterType,
dimension, xSize, ySize, numChannels, imageType,
name));
}
/**************************************************************************
*
* Function: impOpenFdExt
*
* Description: Opens an SGI image file specified by descriptor for reading
* or writing. The Ext (extended) form of the impOpenFd function
* allows an offset into the image file to be specified. In addition
* the image may be cached in memory when in read-only mode.
*
* Parameters:
* fd (I) - descriptor of the file.
* mode (I) - "r" for read-only, "w" for write-only. Read-write
* mode is not currently supported. Note that mode
* must be compatible with the mode on fd.
* offset (I) - number of bytes from the start of the file where
* reading or writing is to begin.
* cache (I) - if IMPCache and mode is read-only, the entire image
* will be cached in memory. If IMPNoCache or
* mode is write-only, no caching is done.
*
* If the mode is "w" the following parameters must be specified.
*
* rasterType (I) - raster encoding and bytes per pixel code
* (e.g. IMP_RASTER_VERBATIM1)
* dimesnion (I) - image dimension. Set this to 1 for a colormap,
* 2 for a bw image, and 3 for an rgb image.
* xSize, ySize (I) - image size in pixels.
* numChannels (I) - 1 for colormap or bw image, 3 for rgb.
* imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
* imp.h for additional choices.
* name (I) - optional image name. IMP_NAME_MAX characters maximum.
* Specify as NULL for a default name string.
*
* Return: Pointer to an SGI image file handle if the open is successful.
* NULL is returned and IMPerrno is set if the open fails.
*
**************************************************************************/
/* VARARGS */
IMPImage* impOpenFdExt(int fd, const char *mode, off_t offset,
IMPCacheMode cache, ...)
{
va_list ap;
uint_t rasterType, dimension;
uint_t xSize, ySize;
uint_t numChannels, imageType;
char *name;
struct stat sbuf;
/*
* Sanity check the inputs
*/
assert(mode != NULL);
/*
* Verify that the file descriptor is valid and
* is seekable. To test seekability we check that an
* lseek succeeds and that the descriptor is not connected
* to a tty. It turns out that the lseek test succeeds for
* a tty so we add the isatty test.
*/
if (fstat(fd, &sbuf) < 0)
_impReturnErrorPtr(IMP_ERR_BADFD);
if (lseek(fd, 0L, SEEK_CUR) < 0 || isatty(fd))
_impReturnErrorPtr(IMP_ERR_SEEK);
/*
* Get the arguments for the actual open function
*/
if (*mode == 'w') {
va_start(ap, cache);
rasterType = va_arg(ap, uint_t);
dimension = va_arg(ap, uint_t);
xSize = va_arg(ap, uint_t);
ySize = va_arg(ap, uint_t);
numChannels = va_arg(ap, uint_t);
imageType = va_arg(ap, uint_t);
name = va_arg(ap, char*);
va_end(ap);
/*
* We do not do caching for image writes
*/
cache = IMPNoCache;
}
/*
* Call the actual open function
*/
return (openImage(fd, NULL, NULL, mode, offset, cache, rasterType,
dimension, xSize, ySize, numChannels, imageType,
name));
}
/**************************************************************************
*
* Function: impOpenBufExt
*
* Description: Opens an SGI image file specified in a memory buffer for
* reading or writing. The Ext (extended) form of the impOpenBuf function
* allows an offset into the image file to be specified.
*
* The user must not deallocate the buffer until all libimp operations
* are completed and impClose has been called.
*
* Parameters:
* buf (I) - buffer containing the image
* mode (I) - "r" for read-only, "w" for write-only. Read-write
* mode is not currently supported. Note that mode
* must be compatible with the mode on fd.
* offset (I) - number of bytes from the start of the file where
* reading or writing is to begin.
*
* If the mode is "w" the following parameters must be specified.
*
* rasterType (I) - raster encoding and bytes per pixel code
* (e.g. IMP_RASTER_VERBATIM1)
* dimesnion (I) - image dimension. Set this to 1 for a colormap,
* 2 for a bw image, and 3 for an rgb image.
* xSize, ySize (I) - image size in pixels.
* numChannels (I) - 1 for colormap or bw image, 3 for rgb.
* imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
* imp.h for additional choices.
* name (I) - optional image name. IMP_NAME_MAX characters maximum.
* Specify as NULL for a default name string.
*
* Return: Pointer to an SGI image file handle if the open is successful.
* NULL is returned and IMPerrno is set if the open fails.
*
**************************************************************************/
/* VARARGS */
IMPImage* impOpenBufExt(void *buf, const char *mode, off_t offset, ...)
{
uint_t rasterType, dimension;
uint_t xSize, ySize;
uint_t numChannels, imageType;
char *name;
/*
* Sanity check the inputs
*/
assert(buf != NULL);
assert(mode != NULL);
/*
* Image write to a buffer not currently supported. This is because
* it is not possible to know up front how big the buffer should be
* before you write into it. This is due to RLE compressarion possibly
* making the file larger than its dimensions would suggest.
*/
if (*mode == 'w')
_impReturnErrorPtr(IMP_ERR_NOWRITE);
/*
* Call the actual open function
*/
return (openImage(0, NULL, buf, mode, offset, _IMPBufDirect, rasterType,
dimension, xSize, ySize, numChannels, imageType,
name));
}
/*
=========================================================================
LOCAL FUNCTIONS
=========================================================================
*/
/**************************************************************************
*
* Function: openImage
*
* Description: Performs the actual job of opening an SGI Image file.
* The file may be specified as either a filename or file
* descriptor.
*
* Parameters:
* fd (I) - descriptor of open file
* fname (I) - name of the file to open. If NULL, fd or buf will be used.
* buf (I) - buffer to open. If NULL, fd or fname will be used.
* mode (I) - "r" for read-only, "w" for write-only. Note that if
* fd is specified it must have permissions compatible
* with mode.
* offset (I) - offset into file to begin reading or writing.
* cache (I) - if IMPCache and read-only, entire image is cached in
* memory.
*
* The following are ignored if open is "r"
*
* rasterType (I) - raster encoding and bytes per pixel code
* (e.g. IMP_RASTER_VERBATIM1)
* dimension (I) - image dimension. Set this to 1 for a colormap,
* 2 for a bw image, and 3 for an rgb image.
* xSize, ySize (I) - image size in pixels.
* numChannels (I) - 1 for colormap or bw image, 3 for rgb.
* imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
* imp.h for additional choices.
* name (I) - optional image name. IMP_NAME_MAX characters maximum.
* Specify as NULL for a default name string.
*
* Return: Pointer to an SGI image file handle if the open is successful.
* NULL is returned and IMPerrno is set if the open fails.
*
**************************************************************************/
static IMPImage* openImage(int fd, const char *fname, void *buf,
register const char *mode,
off_t offset, IMPCacheMode cache,
uint_t rasterType, uint_t dimension,
uint_t xSize, uint_t ySize,
uint_t numChannels, uint_t imageType, char *name)
{
register IMPImage *image;
__uint32_t offsetTags;
/*
* Sanity check the mode setting
*/
if (mode[1] == '+')
_impReturnErrorPtr(IMP_ERR_READWRITE);
/*
* Allocate space for the header that we will return as the
* image handle if all goes well.
*/
if ((image = (IMPImage*)calloc(1, sizeof(IMPImage))) == NULL)
_impReturnErrorPtr(IMP_ERR_MEMALLOC);
/*
* WRITE: If we are writing, we initialize and write the header
*/
if (*mode == 'w') {
/*
* Create the file if necessary
*/
if (fname)
fd = creat(fname, 0666);
if (fd < 0) {
IMPerrno = errno;
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMPerrno);
}
/*
* Initialize disk archived header fields and write the header
*/
impMagic(image) = IMP_MAGIC;
impRasterType(image) = (ushort_t)rasterType;
impImageType(image) = imageType;
impMinValue(image) = SHRT_MAX;
impMaxValue(image) = SHRT_MIN;
image->wastebytes = 0;
image->dorev = 0;
(void)strncpy(image->name, (name)? name: "no name", IMP_NAME_MAX);
image->name[IMP_NAME_MAX - 1] = '\0';
impXSize(image) = (ushort_t)xSize;
impYSize(image) = 1;
impNumChannels(image) = 1;
if (dimension > 1)
impYSize(image) = (ushort_t)ySize;
if (dimension > 2)
impNumChannels(image) = (ushort_t)numChannels;
if (impNumChannels(image) == 1) {
impDimension(image) = 2;
if (impYSize(image) == 1)
impDimension(image) = 1;
} else
impDimension(image) = 3;
impTags(image) = (IMPTag *) NULL;
if (writeData(fd, image, sizeof(IMPImage), offset) !=
sizeof(IMPImage)) {
IMPerrno = errno;
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMPerrno);
}
}
/*
* READ: If we are reading, we read the header and do sanity checks
*/
else {
int retv;
/*
* Open the file if necessary
*/
if (buf == NULL) {
if (fname)
fd = open(fname, O_RDONLY);
if (fd < 0) {
IMPerrno = errno;
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMPerrno);
}
}
/*
* Read the image header. Note that we need to reinit the
* pointers in the structure since reading the disk header
* can change them from NULL.
*/
retv = readData(fd, buf, image, sizeof(IMPImage), offset);
image->tmpbuf = NULL;
image->rowstart = NULL;
image->rowsize = NULL;
if (retv != sizeof(IMPImage)) {
IMPerrno = errno;
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMPerrno);
}
/*
* Determine if this image file needs byte swapping.
* If it does, we need to swap the bytes of the disk
* relevant portions of the header we just read.
*/
if (_impSwapShort(impMagic(image)) == IMP_MAGIC) {
image->dorev = 1;
_impSwapHeader(image);
} else
image->dorev = 0;
/*
* Verify that this is an SGI Image file
*/
if (impMagic(image) != IMP_MAGIC) {
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMP_ERR_BADMAGIC);
}
if (!impIsRLE(image) && !impIsVERBATIM(image)) {
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMP_ERR_BADRASTER);
}
if (impImageType(image) > IMP_IMAGE_COLORMAP) {
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMP_ERR_BADIMAGE);
}
}
/*
* Are there extension tags?
*/
if(readData(fd, buf, &offsetTags, sizeof(__uint32_t),
offset + IMP_TAG_PTR_OFFSET) == sizeof(__uint32_t)) {
if(image->dorev)
_impSwapLongs(&offsetTags, sizeof(long));
if (offsetTags != 0)
getTags(image, fd, buf, offset, offsetTags);
}
/*
* If the raster encoding is RLE, there is some additional
* processing
*/
if (impIsRLE(image)) {
if (initRLE(image, fd, buf, mode, offset) < 0) {
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMPerrno);
}
}
/*
* Allocate scratch storage for row operations
*/
if ((image->tmpbuf = _impBufferAlloc(image)) == NULL) {
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMP_ERR_MEMALLOC);
}
/*
* Initialize image header fields used in core
*/
image->file = (buf) ? -1: fd;
image->flags = (*mode == 'w') ? _IOWRT: _IOREAD;
image->cnt = 0;
image->ptr = NULL;
image->base = NULL;
image->x = image->y = image->z = 0;
image->offset = offset + _IMP_TABLES_START;
image->start = offset;
image->cache = cache;
image->cachebuf = NULL;
image->cachesize = 0;
image->cacheoffset = 0;
/*
* If we are performing image caching, set up the cache.
* Otherwise prepare for disk based processing.
*/
if (cache != IMPNoCache) {
/*
* We cache only the image data. This requires that we add an
* offset when determining our position in the data since the cache
* will not necessarily be aligned with the start of the file.
*/
setCacheSize(image);
/*
* If we are heap caching, allocate space and read in the data
*/
if (cache == IMPHeapCache) {
if ((image->cachebuf = malloc(image->cachesize)) == NULL) {
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMP_ERR_MEMALLOC);
}
if (readData(image->file, buf, image->cachebuf, image->cachesize,
image->cacheoffset) != image->cachesize) {
IMPerrno = errno;
free(image->cachebuf);
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMPerrno);
}
}
/*
* If we are memory mapping, simply do the mmap
*/
else if (cache == IMPMapCache) {
image->cachebuf = mmap(NULL, image->cachesize, PROT_READ,
MAP_SHARED, image->file, image->cacheoffset);
if (image->cachebuf == (void*)-1) {
IMPerrno = errno;
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMPerrno);
}
}
/*
* If we have a user buffer we just point to that
*/
else if (cache == _IMPBufDirect) {
image->cachebuf = ((char*)buf) + image->cacheoffset;
}
}
/*
* Seek to start of image row table
*/
else {
if (lseek(image->file, image->offset, SEEK_SET) < 0) {
IMPerrno = errno;
errorCleanup(image, fd, fname);
_impReturnErrorPtr(IMPerrno);
}
}
return image;
}
/**************************************************************************
*
* Function: initRLE
*
* Description: Initializes the Run Length Encoding tables. We allocate
* space for the tables. If we are writing the image, we initialize
* the tables to known values. If we are reading the image, we seek
* to the tables, read them and swap their bytes, if necessary.
*
* Parameters:
* image (I) - pointer to an image structure
* fd (I) - image file descriptor
* buf (I) - image buffer
* mode (I) - read/write flag
* offset (I) - image start offset
*
* Return: 0 if successful. -1 if errors have been encountered. IMPerrno
* will be set by this function if errors have occurred.
*
**************************************************************************/
static int initRLE(IMPImage *image, int fd, void *buf,
const char *mode, off_t offset)
{
int rleTableSize;
/*
* Allocate RLE location and size tables
*/
rleTableSize = impYSize(image) * impNumChannels(image) * sizeof(__int32_t);
image->rowstart = (__uint32_t*)malloc(rleTableSize);
image->rowsize = (__int32_t*)malloc(rleTableSize);
if (image->rowstart == NULL || image->rowsize == NULL)
_impReturnError(IMP_ERR_MEMALLOC);
image->rleend = _IMP_TABLES_START + (rleTableSize << 1);
/*
* WRITE: If we are writing, we initialize the tables
*/
if (*mode == 'w') {
register int nTable = rleTableSize / sizeof(__int32_t);
register int i;
for (i = 0; i < nTable; i++) {
image->rowstart[i] = 0;
image->rowsize[i] = -1;
}
}
/*
* READ: If we are reading, read the tables and swap bytes
* if necessary.
*/
else {
if (readData(fd, buf, image->rowstart, rleTableSize,
offset + _IMP_TABLES_START) != rleTableSize)
_impReturnError(errno);
if (readData(fd, buf, image->rowsize, rleTableSize,
offset + _IMP_TABLES_START + rleTableSize)
!= rleTableSize)
_impReturnError(errno);
if (image->dorev) {
_impSwapLongs(image->rowstart, rleTableSize);
_impSwapLongs((__uint32_t*)image->rowsize, rleTableSize);
}
}
return 0;
}
/**************************************************************************
*
* Function: errorCleanup
*
* Description: Ensures that we deallocate storage before we return due
* to an error condition.
*
* Parameters:
* image (I) - pointer to an allocated image structure.
* fd (I) - file descriptor of image file.
* fname (I) - name of image file or NULL.
*
* Return: none
*
**************************************************************************/
static void errorCleanup(IMPImage *image, int fd, const char *fname)
{
/*
* Close the image file if we opened it and it is valid
*/
if (fname && (fd >= 0))
(void)close(fd);
/*
* Free the allocated image structure fields and the
* image structure itself
*/
if (image->rowstart)
free(image->rowstart);
if (image->rowsize)
free(image->rowsize);
if (image->tmpbuf)
free(image->tmpbuf);
free(image);
}
/**************************************************************************
*
* Function: readData
*
* Description: A wrapper around the read function that allows us to
* specify an offset from the beginning of the file.
*
* Parameters:
* fd (I) - file descriptor from which to read
* fromBuf (I) - if not NULL this buffer will be read instead of fd
* toBuf (I) - buffer to fill with read data
* amount (I) - number of bytes to read
* offset (I) - offset from beginning of file where data is to be read.
*
* Return: Number of bytes read if no error or -1 if error.
*
**************************************************************************/
static int readData(int fd, void *fromBuf, void *toBuf,
unsigned int amount, off_t offset)
{
if (fromBuf) {
memcpy(toBuf, &((char*)fromBuf)[offset], amount);
return (int)amount;
}
if (lseek(fd, offset, SEEK_SET) == -1)
return -1;
return read(fd, toBuf, amount);
}
/**************************************************************************
*
* Function: writeData
*
* Description: A wrapper around the write function that allows us to
* specify an offset from the beginning of the file.
*
* Parameters:
* fd (I) - file descriptor from which to read
* fromBuf (I) - buffer to write
* amount (I) - number of bytes to write
* offset (I) - offset from beginning of file where data is to be written.
*
* Return: Number of bytes written if no error or -1 if error.
*
**************************************************************************/
static int writeData(int fd, void *fromBuf, unsigned int amount, off_t offset)
{
if (lseek(fd, offset, SEEK_SET) == -1)
return -1;
return write(fd, fromBuf, amount);
}
/**************************************************************************
*
* Function: setCacheSize
*
* Description: Sets the cache size and offset fields of the specified
* image structure. For heap cacheing the cache size is calculated
* as the size of the raw image data. In this case the cache offset
* is the position of the start of the iamge data (i.e. table start
* plus size of tables). If we are memory mapping the file the offset
* is the closest page and the cache size is the amount of raw image
* data plus the slop due to page alignment.
*
* Parameters:
* image (I) - SGI image structure
*
* Return: Size in bytes to store the entire image.
*
**************************************************************************/
static void setCacheSize(IMPImage *image)
{
/*
* If the image is RLE compressed, sum the rowsize array to get the
* total image data size. The offset is the max header size and the
* size of the tables.
*/
if (impIsRLE(image)) {
int i;
int num = impYSize(image) * impNumChannels(image);
for (i = 0, image->cachesize = 0; i < num; i++)
image->cachesize += image->rowsize[i];
image->cacheoffset = image->start + _IMP_TABLES_START +
2 * num * sizeof(__int32_t);
}
/*
* Otherwise the image is verbatim and we calculate the size directly
*/
else {
image->cachesize = impXSize(image) * impYSize(image) *
impNumChannels(image) * impRasterBPP(image);
image->cacheoffset = image->start + _IMP_TABLES_START;
}
/*
* If we are memory mapping the file we need to align the cache on
* a page boundary so we adjust the cache offset and size accordingly.
*/
if (image->cache == IMPMapCache) {
int adjust = image->cacheoffset % getpagesize();
image->cachesize += adjust;
image->cacheoffset -= adjust;
}
}
/**************************************************************************
*
* Function: getTags
*
* Description: Reads any extension tags that are appended to the image.
* If tags are present, the image structure is intialized to
* point to them.
*
* Parameters:
* image (I) - SGI image structure
* fd (I) - image file descriptor
* buf (I) - image buffer
* offset (I) - start of image data on file
* offsetTags (I) - where the tags begin
*
* Return: nothing
*
**************************************************************************/
static void getTags(IMPImage *image, int fd, void *buf, off_t offset,
__uint32_t offsetTags)
{
IMPTag dummyTag;
char test[4];
char *magic="tags";
off_t localOffset;
localOffset = offset + offsetTags;
if(readData(fd, buf, &dummyTag.header, sizeof(IMPTagHeader),
localOffset) != sizeof(IMPTagHeader))
return;
localOffset += sizeof(IMPTagHeader);
if(readData(fd, buf, test, 4, localOffset) != 4)
return;
localOffset += 4;
if(image->dorev) {
_impSwapLongs((__uint32_t *) &dummyTag.header,
sizeof(IMPTagHeader));
_impSwapLongs((__uint32_t *) test, 1);
}
if( (dummyTag.header.tagname != IMP_TAG_FIRST_TAG) ||
(dummyTag.header.length != strlen(magic)) ||
strncmp(test, magic, 4) != 0) {
/* We don't actually have any extension tags */
impTags(image) = (IMPTag *) 0;
} else {
IMPTag **prevTagPtr, *pTag;
prevTagPtr = &image->tags;
pTag = malloc(sizeof(IMPTag));
if(readData(fd, buf, &pTag->header, sizeof(IMPTagHeader),
localOffset) != sizeof(IMPTagHeader))
return;
/* XXX is there a byte swapping problem here? */
localOffset += sizeof(IMPTagHeader);
while(pTag->header.tagname != IMP_TAG_LAST_TAG) {
pTag->data = malloc(pTag->header.length);
*prevTagPtr = pTag;
if(readData(fd, buf, pTag->data, pTag->header.length, localOffset)
!= pTag->header.length)
return;
localOffset += pTag->header.length;
prevTagPtr = &pTag->next;
pTag = malloc(sizeof(IMPTag));
if(readData(fd, buf, pTag, sizeof(IMPTagHeader), localOffset) !=
sizeof(IMPTagHeader))
return;
localOffset += sizeof(IMPTagHeader);
}
/* We don't actually want to save the final null pointer */
*prevTagPtr = (IMPTag *) NULL;
free(pTag);
}
}